/*
	Handles conversion of data into network byte order and vice versa.
*/

#include 	<stdio.h>
#include 	<stdlib.h>
#include 	<string.h>
#include 	<stdint.h>
#include 	<sys/types.h>
#include 	<sys/uio.h>
#include 	<unistd.h>
#include 	<arpa/inet.h>
#include 	<errno.h>
#include 	"types.h"
#include 	"packet.h"
#include 	"player.h"
#include 	"net.h"
#include	"state.h"
#include	"object.h"


int updateState;
Team Teams[NUMTEAMS];
Object Objects[NUMOBJS];

void sendCellUpdateToAll( CellUpdateBody *cub );
void sendPlayerUpdateToAll( int sockfd, PlayerUpdateBody *pub );

/* Game Update Body */
/* Send to all players */
void sendCellUpdateToAll( CellUpdateBody *cub ) {
	// number of updates
	int numCellUpdates = 1;
	//updateState++;
	
	int bodyLength = CELL_UPDATE_HEADER_LENGTH + (numCellUpdates*CELL_UPDATE_BODY_LENGTH);
	char data[CTF_HEADER_LENGTH + bodyLength +1];
	printf("cell update\n");
	// ctf packet header
	*( (short *) &data[0] ) = htons( 0 );
	*( (short *) &data[2] ) = htons( CELL_UPDATE );
	*(  (long *) &data[4] ) = htonl( updateState );	// NEEDS TO CHANGE
	*(  (long *) &data[8] ) = htonl( bodyLength );
	
	*( (long *) &data[12] ) = htonl(numCellUpdates);
	
	// appending 1 update only
	*( (short *) &data[16] ) = htons( cub->pos.row );
	*( (short *) &data[18] ) = htons( cub->pos.col );
	*( (short *) &data[20] ) = htons( cub->cellType );
	*( (short *) &data[22] ) = htons( cub->occupiedByPlayer );
	*( (short *) &data[24] ) = htons( cub->occupiedByObject );
	
	
	// send out to all clients
	int i;
	for (i=0; i<NUMTEAMS; i++){
		Player *playerPtr = Teams[i].playerListPtr;
		if ( playerPtr == NULL )
			continue;	
		do {
			//if ( playerPtr->id != p->id ) {
			//	printf("\t\t playerId %i moved\n",playerPtr->id);
				int sock = playerPtr->socketId;
				write( sock, data, CTF_HEADER_LENGTH + bodyLength );
			//}
			playerPtr = playerPtr->next;
		} while ( playerPtr != NULL);
	}
}



void broadcastChatMsg( char *msg, int length, int senderId ) {
	// number of updates
	//int numCellUpdates = 1;
	//updateState++;
	
	int bodyLength = length + 2;
	char data[CTF_HEADER_LENGTH + bodyLength +1];
	printf("broadcast chat\n");
	// ctf packet header
	*( (short *) &data[0] ) = htons( 0 );
	*( (short *) &data[2] ) = htons( CHAT_MSG_BROADCAST );
	*(  (long *) &data[4] ) = htonl( updateState );	// NEEDS TO CHANGE
	*(  (long *) &data[8] ) = htonl( bodyLength );
	*( (short *) &data[12] ) = htons( senderId );
	printf("msg : [%s]\n", msg);
	memcpy( &data[14], msg, bodyLength );
	
	// send out to all clients
	int i;
	for (i=0; i<NUMTEAMS; i++){
		Player *playerPtr = Teams[i].playerListPtr;
		if ( playerPtr == NULL )
			continue;	
		do {
			//if ( playerPtr->id != p->id ) {
			//	printf("\t\t playerId %i moved\n",playerPtr->id);
				int sock = playerPtr->socketId;
				write( sock, data, CTF_HEADER_LENGTH + bodyLength );
			//}
			playerPtr = playerPtr->next;
		} while ( playerPtr != NULL);
	}
}


void sendInitialCellUpdates() {
//	int numCellUpdates = numPlayers;	// update all player positios
	updateState++;
	
//	int bodyLength = CELL_UPDATE_HEADER_LENGTH + (numCellUpdates*CELL_UPDATE_BODY_LENGTH);
//	char data[CTF_HEADER_LENGTH + bodyLength +1];
	
	// PLAYERS
	int i;
	for (i=0; i<NUMTEAMS; i++){
		Player *playerPtr = Teams[i].playerListPtr;
		if ( playerPtr == NULL )
			continue;
printf("about to do while made cell body for player\n");			
		do {
		
			int cType;
			if ( CELL_IS_FREE(playerPtr->cellPtr) )
				cType = 0;
			else if (  CELL_IS_WALL(playerPtr->cellPtr) )
				cType = 1;
			else if (  CELL_IS_A_HOME(playerPtr->cellPtr) )
				cType = 2;
			else if (  CELL_IS_A_JAIL(playerPtr->cellPtr) )
				cType = 3;
			printf("made cell body for player\n");
			// make cell update body
			/*
			CellUpdateBody *cub;
			cub->pos.row = playerPtr->cellPtr->pos.row ;
			cub->pos.col = playerPtr->cellPtr->pos.col ;
			cub->cellType = cType;
			cub->occupiedByPlayer = playerPtr->id ;
			cub->occupiedByObject = 0;
			*/
			CellUpdateBody cub;
			cub.pos.row = playerPtr->cellPtr->pos.row ;
			cub.pos.col = playerPtr->cellPtr->pos.col ;
			cub.cellType = cType;
			cub.occupiedByPlayer = playerPtr->id ;
			cub.occupiedByObject = 0;
			
			printf("send update of player %i to all\n", playerPtr->id);
			sendCellUpdateToAll( &cub );
			
			playerPtr = playerPtr->next;
		} while ( playerPtr != NULL);
	}
	
	
	// OBJECTS
	printf("finished player, on to object\n");
	for( i=0; i < NUMOBJS; i++ ) {
		printf("object i %i\n", i);
		Object *playerPtr = &Objects[i];
		

			 
			// make cell update body
			CellUpdateBody cub2;
			cub2.pos.row = playerPtr->cellPtr->pos.row ;
			cub2.pos.col = playerPtr->cellPtr->pos.col ;
			cub2.cellType =0;
			cub2.occupiedByPlayer = 0;
			cub2.occupiedByObject = (i+1) ;	// type of object
			
			printf("send update of object %i to all\n", (i+1));
			sendCellUpdateToAll( &cub2 );
			
	}
	
}

void sendCellUpdateMove(int sockfd, Position p, int playerId) {
	// number of updates
	int numCellUpdates = 1;
	
	
	int bodyLength = CELL_UPDATE_HEADER_LENGTH + (numCellUpdates*CELL_UPDATE_BODY_LENGTH);
	char data[CTF_HEADER_LENGTH + bodyLength +1];
	printf("cell update\n");
	// ctf packet header
	*( (short *) &data[0] ) = htons( 0 );
	*( (short *) &data[2] ) = htons( CELL_UPDATE );
	*(  (long *) &data[4] ) = htonl( updateState );	// NEEDS TO CHANGE
	*(  (long *) &data[8] ) = htonl( bodyLength );
	
	*( (long *) &data[12] ) = htonl(numCellUpdates);
	
	// appending 1 update only
	*( (short *) &data[16] ) = htons( p.row );
	*( (short *) &data[18] ) = htons( p.col );
	*( (short *) &data[20] ) = htons( 0 );
	*( (short *) &data[22] ) = htons( playerId );
	*( (short *) &data[24] ) = htons( 0 );
	
	printf("UPDATE CELL MOVE WRITE %i\n", write( sockfd, data, CTF_HEADER_LENGTH + bodyLength ) );
}
/* Game Update Body */
void sendPlayerUpdateToAll( int sockfd, PlayerUpdateBody *pub ) {
	updateState++;
	// number of updates
	int numPlayerUpdates = 0;
	int bodyLength =  PLAYER_UPDATE_HEADER_LENGTH + (numPlayerUpdates*PLAYER_UPDATE_BODY_LENGTH);
	
	char data[CTF_HEADER_LENGTH + bodyLength +1];
	printf("player update\n");
	// ctf packet header
	*( (short *) &data[0] ) = htons( 0 );
	*( (short *) &data[2] ) = htons( PLAYER_UPDATE );
	*(  (long *) &data[4] ) = htonl( updateState );	// NEEDS TO CHANGE
	*(  (long *) &data[8] ) = htonl( bodyLength );
	
	// header
	*( (short *) &data[12] ) = htons(numPlayerUpdates);
	// body
	*( (short *) &data[14] ) = htons( pub->playerId );
	*( (short *) &data[16] ) = htons( pub->field );
	*( (short *) &data[18] ) = htons( pub->value );
	
	
	write( sockfd, data, CTF_HEADER_LENGTH + bodyLength );
}


/* Game Update Body */
void sendGameUpdateToAll( int sockfd, int gameState ) {
	updateState++;
	char data[CTF_HEADER_LENGTH + GAME_UPDATE_BODY_LENGTH +1];
	printf("game update\n");
	// ctf packet header
	*( (short *) &data[0] ) = htons( 0 );
	*( (short *) &data[2] ) = htons( GAME_UPDATE );
	*(  (long *) &data[4] ) = htonl( updateState );	// NEEDS TO CHANGE
	*(  (long *) &data[8] ) = htonl( GAME_UPDATE_BODY_LENGTH );
	
	// game state
	*( (short *) &data[12] ) = htons(gameState);
	
	// send out to all clients
	int i;
	for (i=0; i<NUMTEAMS; i++){
		Player *playerPtr = Teams[i].playerListPtr;
		if ( playerPtr == NULL )
			continue;	
		do {
			int sock = playerPtr->socketId;
			write( sock, data, CTF_HEADER_LENGTH + GAME_UPDATE_BODY_LENGTH );

			playerPtr = playerPtr->next;
		} while ( playerPtr != NULL);
	}
}
